/*
    DIMVisual, the Data Integration Model for Visualization of trace files.
    Copyright (c) 2008 Lucas Mello Schnorr <schnorr@gmail.com>

    This file is part of DIMVisual.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "IntegratorExec.h"

@implementation IntegratorExec

- (id) initWithCommand: (Command *) command
{
	int i;
	self = [super init];


	/* Phase X: Configuring the Integrator core */
	NSDictionary *selfConf = [[command configuration] objectForKey: @"DIMVISUAL"];
	outputFile = [selfConf objectForKey: @"output"];

	if (outputFile == nil){
		NSLog (@"DIMVisual: output file not specified with -output");
		return nil;
	}

	[outputFile retain];
        ordering = [[Order alloc] init];

	/* Phase X: Configuring the Data Sources loaded */
	NSDictionary *bundleConf = [[command configuration] objectForKey: @"Bundles"];
	NSArray *allDataSources = [bundleConf allKeys];
	NSMutableArray *hierarchies = [[NSMutableArray alloc] init];
	for (i = 0; i < [allDataSources count]; i++){
		NSString *name = [allDataSources objectAtIndex: i];
		NSDictionary *conf=[bundleConf objectForKey: name];
		id<DataSource> ds;

		ds = [[NSClassFromString (name) alloc] initWithProvider: self];
		if ([ds setConfiguration: conf] == NO){
			NSLog (@"DIMVisual: error during bundle configuration. "
				"This message comes from %s:%d.", __FILE__,
				__LINE__);
			return nil;
		}else{
			[ordering add: ds];
			[hierarchies addObject: [ds hierarchy]];
		}
	}

	hierarchy =  [[PajeHierarchy alloc] initFromDictionary:
				[self mergeHierarchies: hierarchies]];
	if (hierarchy == nil){
		NSLog (@"DIMVisual: Problem when creating hierarchy.");
		return nil;
	}
	containers = [[NSMutableDictionary alloc] init];
	NSArray *hdefined = [hierarchy entityOfType: @"container"];
	[containers setObject: [NSMutableSet set] forKey: @"0"];
	for (i = 0; i < [hdefined count]; i++){
		[containers setObject: [NSMutableSet set] forKey: [hdefined objectAtIndex: i]];
	}
	return self;
}

/*
 *
 */
- (void) convert
{
        NSFileManager *fileManager = [NSFileManager defaultManager];
	NSMutableArray *ar, *ret;
	PajeHeaderCenter *headcenter;
	long long i;
	NSString *str;
	NSFileHandle *temporary;
	NSFileHandle *output;
	NSString *tempFN = [NSString stringWithFormat: @"%@-temp", outputFile];
	if ([fileManager createFileAtPath: outputFile contents: nil
			attributes: nil] == NO){
			NSLog (@"error on %s", __FUNCTION__);
	}

								
	if ([fileManager createFileAtPath: tempFN contents: nil
			attributes: nil] == NO){
			NSLog (@"error on %s", __FUNCTION__);
	}
	
	temporary = [NSFileHandle fileHandleForWritingAtPath: tempFN];

	headcenter = [[PajeHeaderCenter alloc] init];
	/* Hierarchy */
	ar = [hierarchy hierarchy];
	[ar retain];
	for (i = 0; i < [ar count]; i++){
		NSData *data;
		[headcenter addHeader: [[ar objectAtIndex: i] header]];
		str = [[ar objectAtIndex: i] printWithProvider: headcenter];
		data = [[NSData alloc] initWithData: 
				[[NSString stringWithFormat: @"%@\n", str]
				dataUsingEncoding: NSASCIIStringEncoding]];
		[temporary writeData: data];
		[temporary synchronizeFile];
		[data release];
	}
	[ar release];

	
	/* Events */
	NSLog (@"Integrator: Starting main loop...");
	NSDate *start = [[NSDate alloc] init];	
	while (1){

		NSDate *end;
		static long long evg = 0;
		
		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
		ret = [ordering convert];
		[ret retain];

		if (ret == nil){
			break;
		}
		for (i = 0; i < [ret count]; i++){
			NSData *data;
			[headcenter addHeader: [[ret objectAtIndex: i] header]];
			str = [[ret objectAtIndex: i] printWithProvider: headcenter];
			data = [[NSData alloc] initWithData:
				[[NSString stringWithFormat: @"%@", str]
				dataUsingEncoding: NSASCIIStringEncoding]];
			[temporary writeData: data];
			[data release];
			data = nil;
		}
		end = [NSDate date];
		evg += [ret count];
		double t = [end timeIntervalSinceDate:start];
		if (t > 5){
			[start release];
			start = [[NSDate alloc] init];
			NSLog (@"Integrator: output is %f e/s", evg/t);
			evg = 0;
		}
		[ret release];
		
		ret = nil;

		[pool release];
	}
	NSLog (@"Integrator: Ending main loop...");
	NSLog (@"Integrator: Recording...");
	str = [headcenter print];
	[temporary closeFile];
	temporary = [NSFileHandle fileHandleForReadingAtPath: tempFN];
	output = [NSFileHandle fileHandleForWritingAtPath: outputFile];
	[output writeData: [str dataUsingEncoding: NSASCIIStringEncoding]];
	[output writeData: [temporary availableData]];
	[output closeFile];
	[temporary closeFile];
	NSLog (@"Integrator: File %@ closed.", outputFile);

	if ([fileManager removeFileAtPath: tempFN handler: nil] == NO){
			NSLog (@"error on %s", __FUNCTION__);
	}
	[headcenter release];
}

@end
